package com.ruoyi.business.listener;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.base.domain.BaseBsZd;
import com.ruoyi.base.mapper.BaseBsZdMapper;
import com.ruoyi.cm.domain.CmBsProcessInspection;
import com.ruoyi.cm.domain.CmPeriodMeasurement;
import com.ruoyi.cm.domain.bo.CmBaContractSheetsBo;
import com.ruoyi.cm.domain.bo.CmBsContractInfoBo;
import com.ruoyi.cm.domain.bo.CmBsStartAdvanceBo;
import com.ruoyi.cm.domain.bo.CmReportBo;
import com.ruoyi.cm.domain.vo.CmBaContractSheetsVo;
import com.ruoyi.cm.mapper.CmBsProcessInspectionMapper;
import com.ruoyi.cm.mapper.CmPeriodMeasurementMapper;
import com.ruoyi.cm.service.ICmBaContractSheetsService;
import com.ruoyi.cm.service.ICmBsContractInfoService;
import com.ruoyi.cm.service.ICmBsStartAdvanceService;
import com.ruoyi.cm.service.ICmReportService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.wecom.client.WeComUtils;
import com.ruoyi.common.wecom.constants.WeComUrlConstants;
import com.ruoyi.ma.domain.MaMaterialPlan;
import com.ruoyi.ma.domain.MaReportFormPayment;
import com.ruoyi.ma.domain.bo.MaMaterialPlanBo;
import com.ruoyi.ma.domain.bo.MaReportFormPaymentBo;
import com.ruoyi.ma.mapper.MaMaterialPlanMapper;
import com.ruoyi.ma.service.IMaMaterialPlanService;
import com.ruoyi.ma.service.IMaReportFormPaymentService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.workflow.domain.vo.WfDetailVo;
import com.ruoyi.workflow.service.IWfProcessService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.common.engine.api.delegate.event.FlowableEventType;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ruoyi.business.constant.BusinessConstants.*;
import static com.ruoyi.flowable.common.constant.TaskConstants.PROCESS_INITIATOR;

/**
 * Flowable 全局监听器
 * 注册到任务 完成时
 *
 * @author zyb
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CompleteTaskListener implements FlowableEventListener {


    private final TaskService taskService;
    private final WeComUtils weComUtils;
    private final ISysUserService userService;
    private final ICmBsStartAdvanceService cmBsStartAdvanceService;

    private final ICmBaContractSheetsService iCmBaContractSheetsService;

    private final ICmBsContractInfoService iCmBsContractInfoService;
    private final IMaMaterialPlanService planService;
    private final IMaReportFormPaymentService paymentService;

    //报表管理
    private final ICmReportService reportService;
    private final CmBsProcessInspectionMapper processInspectionMapper;

    private final IWfProcessService processService;

    @Resource
    protected HistoryService historyService;

    private final BaseBsZdMapper zdMapper;
    private final CmPeriodMeasurementMapper periodMeasurementMapper;

    @Override
    public Collection<? extends FlowableEventType> getTypes() {
        return null;
    }

    @Override
    public void onEvent(FlowableEvent flowableEvent) {
        TaskEntity taskEntity = (TaskEntity) ((FlowableEntityEventImpl) flowableEvent).getEntity();
        // 如果是发起人自己的完成 直接跳过
        if (("faqiren".equals(taskEntity.getTaskDefinitionKey()) || "fqr".equals(taskEntity.getTaskDefinitionKey()))) {
            return;
        }
        // 流程实例
        HistoricProcessInstance historicProcIns = historyService.createHistoricProcessInstanceQuery()
            .processInstanceId(taskEntity.getProcessInstanceId()).includeProcessVariables().singleResult();
        // 发起流程的变量
        Map<String, Object> proInstVariables = historicProcIns.getProcessVariables();
        String taskId = taskEntity.getId();
        String procInsId = taskEntity.getProcessInstanceId();
        WfDetailVo wfDetailVo = processService.queryProcessDetail(procInsId, taskId);
        String taskComment = null;
        if (CollUtil.isNotEmpty(wfDetailVo.getHistoryProcNodeList()) && CollUtil.isNotEmpty(wfDetailVo.getHistoryProcNodeList().get(0).getCommentList())) {
            taskComment = wfDetailVo.getHistoryProcNodeList().get(0).getCommentList().get(0).getFullMessage();
        }
        log.debug(taskComment); // taskComment
        // TODO 自定义业务处理：

        if (taskEntity.getProcessDefinitionId().startsWith(GCKZFSHBBSPLC_PROCESS_KEY) && "zhongshen".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 1. 工程款支付审核报表审批流程 ---  终审 审批通过完成后要做XX业务处理
            Long bdId = (Long)proInstVariables.get("bdId");
            Long qsId = (Long)proInstVariables.get("qsId");
            CmReportBo bo =new CmReportBo();
            bo.setBdId(bdId);
            bo.setQsId(qsId);
            bo.setStatus("22");
            reportService.updateStatusByBo(bo);
            log.debug(" 在工程款支付审核报表审批流程中  监理 审批完成 todo 实现相关业务操作");
        }
        if (taskEntity.getProcessDefinitionId().startsWith(GXBYSPLC_PROCESS_KEY) && "zongjian".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 1. 工序报验审批流程 ---  总监 审批通过完成后要做XX业务处理
            Long id = (Long)proInstVariables.get("id");
            CmBsProcessInspection bo =new CmBsProcessInspection();
            bo.setId(id);
            bo.setApproveStatus("22");
            bo.setApprovalOpinions(taskComment);
            processInspectionMapper.updateById(bo);
            log.debug(" 在工序报验审批流程中  总监 审批完成 todo 实现相关业务操作");
        }
        if (taskEntity.getProcessDefinitionId().startsWith(HTSPLC_PROCESS_KEY) && "jianshedanwei".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 2. 合同审批流程  ---- 建设单位 审批通过完成后要做XX业务处理
            Long bdId = (Long) proInstVariables.get("bdId");
            Long contractId = (Long) proInstVariables.get("contractId");
            CmBsContractInfoBo cmBsContractInfoBo = new CmBsContractInfoBo();
            cmBsContractInfoBo.setBdId(bdId);
            cmBsContractInfoBo.setContractId(contractId);
            cmBsContractInfoBo.setApprovalStatus("22");
            iCmBsContractInfoService.updateApprovalStatusByBo(cmBsContractInfoBo);
            log.debug(" 合同审批流程  ---- 建设单位 审批通过完成后要做XX业务处理 ");
        }
        if (taskEntity.getProcessDefinitionId().startsWith(HTBGSPLC_PROCESS_KEY) && "jianshedanwei".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 2. 合同变更审批流程  ---- 建设单位 审批通过完成后要做XX业务处理
            Long bdId = (Long) proInstVariables.get("bdId");
            Long contractId = (Long) proInstVariables.get("contractId");
            CmBsContractInfoBo cmBsContractInfoBo = new CmBsContractInfoBo();
            cmBsContractInfoBo.setBdId(bdId);
            cmBsContractInfoBo.setContractId(contractId);
            cmBsContractInfoBo.setChgApprovalStatus("22");
            iCmBsContractInfoService.updateChgApprovalStatusByBo(cmBsContractInfoBo);
            log.debug(" 合同变更审批流程  ---- 建设单位 审批通过完成后要做XX业务处理 ");
        }
        if (taskEntity.getProcessDefinitionId().startsWith(HTZDQDSPLC_PROCESS_KEY) && "jianshedanwei".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 3. 合同站点清单审批流程  ---- 建设单位 审批通过完成后要做XX业务处理
            Long bdId = (Long) proInstVariables.get("bdId");
            Long zdId = (Long) proInstVariables.get("zdId");
            CmBaContractSheetsBo cmBaContractSheetsBo = new CmBaContractSheetsBo();
            cmBaContractSheetsBo.setBdId(bdId);
            cmBaContractSheetsBo.setZdId(zdId);
            cmBaContractSheetsBo.setApprovalStatus("22");
            iCmBaContractSheetsService.updateApprovalStatusByBo(cmBaContractSheetsBo);
            log.debug(" 合同站点清单审批流程  ---- 建设单位 审批通过完成后要做XX业务处理 ");
        }
        if (taskEntity.getProcessDefinitionId().startsWith(KGYFK_PROCESS_KEY) && "jianshedanwei".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 4. 开工预付款审批流程  ---- 建设单位 审批通过完成后要做XX业务处理
            Long bdId = (Long) proInstVariables.get("bdId");
            CmBsStartAdvanceBo cmBsStartAdvanceBo = new CmBsStartAdvanceBo();
            cmBsStartAdvanceBo.setBdId(bdId);
            cmBsStartAdvanceBo.setReportFlag("22");
            cmBsStartAdvanceService.updateApprovalStatusByBo(cmBsStartAdvanceBo);
            log.debug(" 开工预付款审批流程  ---- 建设单位 审批通过完成后要做XX业务处理 ");
        }
        if (taskEntity.getProcessDefinitionId().startsWith(JGC_PROCESS_KEY) && "jianshedanwei".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 5. 甲供材审批流程  ---- 建设单位 审批通过完成后要做XX业务处理
            Long planId = (Long) proInstVariables.get("planId");
            MaMaterialPlanBo planBo = new MaMaterialPlanBo();
            planBo.setPlanId(planId);
            planBo.setWorkflowsStateus("22");
            planService.updateByBo(planBo);
            log.debug(" 甲供材审批流程  ---- 建设单位 审批通过完成后要做XX业务处理 ");
        }
        if (taskEntity.getProcessDefinitionId().startsWith(JGCBB_PROCESS_KEY) && "jianshedanwei".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 6. 甲供材报表审批流程  ---- 建设单位 审批通过完成后要做XX业务处理
            Long reportId = (Long) proInstVariables.get("reportId");
            MaReportFormPaymentBo paymentBo = new MaReportFormPaymentBo();
            paymentBo.setReportId(reportId);
            paymentBo.setWorkflowsStateus("22");
            paymentService.updateByBo(paymentBo);
            log.debug(" 甲供材报表审批流程  ---- 建设单位 审批通过完成后要做XX业务处理 ");
        }
        if (taskEntity.getProcessDefinitionId().startsWith(HTZDQDBGSPLC_PROCESS_KEY) && "jianshedanwei".equals(taskEntity.getTaskDefinitionKey())) {
            // TODO 7. 合同站点清单变更审批流程  ---- 建设单位 审批通过完成后要做XX业务处理
            Long bdId = (Long) proInstVariables.get("bdId");
            Long zdId = (Long) proInstVariables.get("zdId");
            CmBaContractSheetsBo cmBaContractSheetsBo = new CmBaContractSheetsBo();
            cmBaContractSheetsBo.setBdId(bdId);
            cmBaContractSheetsBo.setZdId(zdId);
            cmBaContractSheetsBo.setChgApprovalStatus("22");
            iCmBaContractSheetsService.updateApprovalStatusByBo(cmBaContractSheetsBo);
            // 合同站点清单变更审批通过后同步更新站点的实际建设容量和实际建设合同额
            LambdaQueryWrapper<BaseBsZd> lqw = Wrappers.lambdaQuery();
            lqw.eq(zdId != null, BaseBsZd::getId, zdId);
            BaseBsZd baseBsZd = zdMapper.selectById(zdId);
            // 获取变更数量合计 变更后合计
            CmBaContractSheetsBo bo = new CmBaContractSheetsBo();
            bo.setBdId(bdId);
            bo.setZdId(zdId);
            Map<String, Object> data = iCmBaContractSheetsService.queryList(bo);
            if (ObjectUtils.isNotEmpty(data.get("total"))) {
                // 更新站点的实际建设容量和实际建设金额
                updateZd(data, baseBsZd);
                // 更新对应的中间计量的变更数量和变更后合计
                updatePeriod(data, bdId, zdId);
            }
            log.debug(" 合同站点清单变更审批流程  ---- 建设单位 审批通过完成后要做XX业务处理 ");
        }
        log.debug("log-debug 有人 审批完成 todo 可以实现相关业务操作");

        // 企业微信相关的操作
//        weComUtils.sendTextMessage(sysUser.getUserName(), WeComUrlConstants.TITLE_1, historicProcIns.getProcessDefinitionName() + ";项目：" + proInstVariables.getOrDefault("projectName", ""), fqrUser.getNickName());
    }

    @Override
    public boolean isFailOnException() {
        return false;
    }

    @Override
    public boolean isFireOnTransactionLifecycleEvent() {
        return false;
    }

    @Override
    public String getOnTransaction() {
        return null;
    }

    // 更新站点的实际建设容量和实际建设金额
    @Transactional
    public void updateZd(Map<String, Object> data, BaseBsZd baseBsZd) {
        Map<String, BigDecimal> total = (Map<String, BigDecimal>) data.get("total");
        BigDecimal rongliangTotal = total.get("rongliangTotal");
        BigDecimal chgRongliangTotal = total.get("chgRongliangTotal");
        BigDecimal chgZongjiaTotal = total.get("chgZongjiaTotal");
        BigDecimal numSum = BigDecimal.ZERO;
        if (ObjectUtils.isNotEmpty(rongliangTotal) && ObjectUtils.isNotEmpty(chgRongliangTotal)) {
            numSum = rongliangTotal.add(chgRongliangTotal).setScale(2, BigDecimal.ROUND_HALF_UP);
        }
        // 实际建设容量 = 数量 + 变更数量
        baseBsZd.setJiansrlActual(numSum);
        // 实际合同额 = 实际建设容量 * 单瓦造价
        BigDecimal danwzj = baseBsZd.getDanwzj();
        if (ObjectUtils.isNotEmpty(danwzj)) {
            BigDecimal res = danwzj.multiply(numSum);
            baseBsZd.setZdContractAmountActual(res);
        }
        // 更新站点
        zdMapper.updateById(baseBsZd);
    }

    // 更新对应的中间计量的变更数量和变更后合计
    @Transactional
    public void updatePeriod(Map<String, Object> data, Long bdId, Long zdId) {
        // 合同清单列列表
        List<CmBaContractSheetsVo> cmBaContractSheetsVos = (List<CmBaContractSheetsVo>) data.get("cmBaContractSheetsVos");
        Map<String, BigDecimal> total = (Map<String, BigDecimal>) data.get("total");
        BigDecimal rongliangTotal = total.get("rongliangTotal");
        BigDecimal chgRongliangTotal = total.get("chgRongliangTotal");
        BigDecimal chgZongjiaTotal = total.get("chgZongjiaTotal");
        // 根据标段和站点获取中间计量表
        LambdaQueryWrapper<CmPeriodMeasurement> lqw = Wrappers.lambdaQuery();
        lqw.eq(bdId != null, CmPeriodMeasurement::getBdId, bdId);
        lqw.eq(zdId != null, CmPeriodMeasurement::getZdId, zdId);
        List<CmPeriodMeasurement> list = periodMeasurementMapper.selectList(lqw);

        // 对比清单和中间计量表,清单和中间计量的变更数量不一致时,将清单的变更数量赋值给中间计量
        if (CollUtil.isNotEmpty(list)) {
            cmBaContractSheetsVos.forEach(item -> {
                BigDecimal afterSl = item.getChgRongliang();
                BigDecimal afterJe = item.getChgZongjia();
                // 相同清单项下
                List<CmPeriodMeasurement> pers = list.stream().filter(e -> e.getContractListId().equals(item.getSheetId())).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(pers)) {
                    pers.forEach(pe -> {
                        // 变更数量不一致
                        if (!afterSl.equals(pe.getChgRongliang())) {
                            BigDecimal beforeSl = pe.getChgRongliang();
                            BigDecimal beforeJe = pe.getChgZongjia();
                            BigDecimal remainingQuantity = pe.getRemainingQuantity();
                            // 剩余数量 = 变更数量后 - 变更数量前 + 剩余数量
                            if (ObjectUtils.isNotEmpty(remainingQuantity) && ObjectUtils.isNotEmpty(afterSl)) {
                                pe.setChgRongliang(afterSl);
                                if (ObjectUtils.isEmpty(beforeSl)) {
                                    pe.setRemainingQuantity(afterSl.add(remainingQuantity));
                                } else {
                                    pe.setRemainingQuantity(afterSl.subtract(beforeSl).add(remainingQuantity));
                                }

                            }
                            pe.setChgRongliang(afterSl);
                            pe.setChgZongjia(afterJe);
                        }
                    });
                    // 更新变更信息
                    periodMeasurementMapper.updateBatchById(pers);
                }

            });
        }

    }
}
